﻿namespace STLTypeVisualizer
{
    using System;
	using System.Collections.Generic;
	using VisualGDBExpressions;

	internal abstract class UMapFilter : TypeListBasedExpressionFilter
	{
		public UMapFilter(params string[] supportedTypes) : base(supportedTypes)
		{
		}

		protected abstract UMapChildProvider CreateChildProvider(IExpressionEvaluator evaluator,
			string Type, ulong initialNodeAddr, IExpression actualMembersNode);

		protected abstract string EvalBuckets(string fullNameForEvaluator, IExpressionEvaluator evaluator);
		protected abstract string EvalSize(string fullNameForEvaluator, IExpressionEvaluator evaluator);

		protected override IExpression DoAttach(IExpression expr, IExpressionEvaluator evaluator)
		{
			string typeOverride;
			string fullNameForEvaluator = expr.FullNameForEvaluator;
			string type = expr.Type;
			StaticExpressionFilter filter1 = expr as StaticExpressionFilter;
			if (filter1 != null)
			{
				typeOverride = filter1.TypeOverride;
			}
			else
			{
				StaticExpressionFilter local1 = filter1;
				typeOverride = null;
			}
			if (typeOverride != null)
			{
				type = (expr as StaticExpressionFilter).BaseExpression.Type;
			}
			char[] trimChars = new char[] { '&' };
			type = type.TrimEnd(trimChars);
			ExpressionValue value2 = evaluator.EvaluateExpression(EvalBuckets(fullNameForEvaluator, evaluator), "void *");
			if (!(value2 is ExpressionValue.Integral))
			{
				return null;
			}
			ExpressionValue value3 = evaluator.EvaluateExpression(EvalSize(fullNameForEvaluator, evaluator), "int");
			string val = !(value3 is ExpressionValue.Integral) ? this.ExpandLabel : $"[{(value3 as ExpressionValue.Integral).Value}个元素]";
			StaticExpressionFilter filter2 = new StaticExpressionFilter(expr);
			filter2.ValueOverride = new ExpressionValue.Custom(val);
			VirtualExpressionNode actualMembersNode = new VirtualExpressionNode("[实际成员]", "", expr.Children);
			actualMembersNode.FixedValue = new ExpressionValue.Composite("{...}");
			filter2.ChildrenOverride = CreateChildProvider(evaluator, type, (value2 as ExpressionValue.Integral).Value, actualMembersNode);
			return filter2;
		}

		protected string ExpandLabel =>
			"[展开以填充std::map]";

		protected abstract class UMapChildProvider : IExpressionChildProvider
		{
			protected IExpressionEvaluator _Evaluator;
			protected string _Type;
			protected ulong _InitialNodeAddr;
			protected IExpression _ActualMembersNode;
			protected bool _UseStorageSyntax;
			protected List<IExpression> _Children;

			public UMapChildProvider(IExpressionEvaluator evaluator, string Type, ulong initialNodeAddr, IExpression actualMembersNode)
			{
				this._Evaluator = evaluator;
				this._Type = Type;
				this._InitialNodeAddr = initialNodeAddr;
				this._ActualMembersNode = actualMembersNode;
			}

			private void LoadChildren()
			{
				if (this._Children == null)
				{
					List<IExpression> list1 = new List<IExpression>();
					list1.Add(this._ActualMembersNode);
					this._Children = list1;
					DateTime now = DateTime.Now;
					for (UMapFilter.Node node = this.QueryNode(this._InitialNodeAddr, false); node != null; node = this.QueryNode(node.NextNodeAddr, false))
					{
						if (node.Value != null)
						{
							IExpression expKey = this._Evaluator.CreateExpression(node.Value + ".first", true);
							IExpression expValue = this._Evaluator.CreateExpression(node.Value + ".second", true);
							StaticExpressionFilter item = new StaticExpressionFilter(node.Value);
							if (expKey != null && expValue != null)
							{
								item.ShortNameOverride = expKey.Value.ToString();
								item.ValueOverride = expValue.Value;
								this._Children.Add(item);
							}
						}
						if (node.NextNodeAddr == this._InitialNodeAddr)
						{
							break;
						}
						if ((DateTime.Now - now).TotalSeconds > 10.0)
						{
							this._Children.Add(new VirtualExpressionNode("[遍历超时]", "", null));
							return;
						}
					}
				}
			}

			public ExpressionChildRange QueryChildren(int firstChild, int childCount)
			{
				ExpressionChildRange range1 = new ExpressionChildRange();
				range1.FirstChildIndex = 0;
				range1.Children = this._Children;
				return range1;
			}

			public int QueryChildrenCount(out ExpressionChildRange additionallyReturnedChildren)
			{
				this.LoadChildren();
				additionallyReturnedChildren = null;
				return ((this._Children == null) ? 0 : this._Children.Count);
			}

			protected abstract string EvalNext(ulong addr);
			protected abstract IExpression EvalValue(ulong addr);
			private UMapFilter.Node QueryNode(ulong addr, bool skipValue)
			{
				ExpressionValue value2 = this._Evaluator.EvaluateExpression(EvalNext(addr), "void *");
				if (!(value2 is ExpressionValue.Integral))
				{
					return null;
				}
				UMapFilter.Node node1 = new UMapFilter.Node();
				node1.NextNodeAddr = (value2 as ExpressionValue.Integral).Value;
				UMapFilter.Node node = node1;
				if (!skipValue)
				{
					node.Value = EvalValue(addr);
					if (node.Value == null)
					{
						return null;
					}
				}
				return node;
			}

			public bool ChildrenAvailable =>
				true;
		}

		private class Node
		{
			public ulong NextNodeAddr;
			public IExpression Value;
		}
	}

	internal class GccUMapFilter : UMapFilter
	{
		static string[] textArray1 = new string[] { "std::unordered_map<", "std::unordered_multimap<" };
		public GccUMapFilter() : base(textArray1)
		{
		}

		protected override UMapChildProvider CreateChildProvider(IExpressionEvaluator evaluator, string Type, ulong initialNodeAddr, IExpression actualMembersNode)
		{
			return new GccUMapChildProvider(evaluator, Type, initialNodeAddr, actualMembersNode);
		}

		protected override string EvalBuckets(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"(void *)(({fullNameForEvaluator})._M_h._M_before_begin->_M_nxt)";
		}

		protected override string EvalSize(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"(void *)(({fullNameForEvaluator})._M_h._M_element_count)";
		}

		protected class GccUMapChildProvider : UMapChildProvider
		{
			public GccUMapChildProvider(IExpressionEvaluator evaluator, string Type, ulong initialNodeAddr, IExpression actualMembersNode)
				: base(evaluator, Type, initialNodeAddr, actualMembersNode)
			{ }

			protected override string EvalNext(ulong addr)
			{
				return $"(void *)((({this._Type}::_Hashtable::__node_type*)0x{addr:x})->_M_nxt)";
			}

			protected override IExpression EvalValue(ulong addr)
			{
				string str = $"((({ this._Type}::_Hashtable::__node_type *)0x{addr:x}))->_M_valptr()";
				return this._Evaluator.CreateExpression(str, false);
			}
		}
	}

	internal class ClangUMapFilter : UMapFilter
	{
		static string[] textArray1 = new string[] { "std::__1::unordered_map<", "std::__1::unordered_multimap<" };
		public ClangUMapFilter() : base(textArray1)
		{
		}

		protected override UMapChildProvider CreateChildProvider(IExpressionEvaluator evaluator, string Type, ulong initialNodeAddr, IExpression actualMembersNode)
		{
			return new ClangUMapChildProvider(evaluator, Type, initialNodeAddr, actualMembersNode);
		}

		protected override string EvalBuckets(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"(void *)(({fullNameForEvaluator}).__table_.__p1_)->__value_";
		}

		protected override string EvalSize(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"(void *)(({fullNameForEvaluator}).__table_.__p2_->__value_)";
		}

		protected class ClangUMapChildProvider : UMapChildProvider
		{
			public ClangUMapChildProvider(IExpressionEvaluator evaluator, string Type, ulong initialNodeAddr, IExpression actualMembersNode)
				: base(evaluator, Type, initialNodeAddr, actualMembersNode)
			{ }

			protected override string EvalNext(ulong addr)
			{
				string str = $"*((({this._Type}::__table::__node_pointer*)0x{addr:x}))";
				return str;
			}

			protected override IExpression EvalValue(ulong addr)
			{
				string str = $"((({this._Type}::__table::iterator::__next_pointer)0x{addr:x})->__upcast()->__value_->__cc)";
				return this._Evaluator.CreateExpression(str, true);
			}
		}
	}
}

